<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>web-sys: Wasm in Web Worker - The `wasm-bindgen` Guide</title>
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="shortcut icon" href="../favicon.png">
        <link rel="stylesheet" href="../css/variables.css">
        <link rel="stylesheet" href="../css/general.css">
        <link rel="stylesheet" href="../css/chrome.css">
        <link rel="stylesheet" href="../css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
        <link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
        <link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="../highlight.css">
        <link rel="stylesheet" href="../tomorrow-night.css">
        <link rel="stylesheet" href="../ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        

        
    </head>
    <body class="light">
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "../";
            var default_theme = "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } 
            if (theme === null || theme === undefined) { theme = default_theme; }
            document.body.className = theme;
            document.querySelector('html').className = theme + ' js';
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <ol class="chapter"><li class="affix"><a href="../introduction.html">Introduction</a></li><li class="spacer"></li><li><a href="../examples/index.html"><strong aria-hidden="true">1.</strong> Examples</a></li><li><ol class="section"><li><a href="../examples/hello-world.html"><strong aria-hidden="true">1.1.</strong> Hello, World!</a></li><li><a href="../examples/console-log.html"><strong aria-hidden="true">1.2.</strong> Using console.log</a></li><li><a href="../examples/add.html"><strong aria-hidden="true">1.3.</strong> Small Wasm files</a></li><li><a href="../examples/without-a-bundler.html"><strong aria-hidden="true">1.4.</strong> Without a Bundler</a></li><li><a href="../examples/synchronous-instantiation.html"><strong aria-hidden="true">1.5.</strong> Synchronous Instantiation</a></li><li><a href="../examples/import-js.html"><strong aria-hidden="true">1.6.</strong> Importing functions from JS</a></li><li><a href="../examples/char.html"><strong aria-hidden="true">1.7.</strong> Working with char</a></li><li><a href="../examples/wasm-in-wasm.html"><strong aria-hidden="true">1.8.</strong> js-sys: WebAssembly in WebAssembly</a></li><li><a href="../examples/dom.html"><strong aria-hidden="true">1.9.</strong> web-sys: DOM hello world</a></li><li><a href="../examples/closures.html"><strong aria-hidden="true">1.10.</strong> web-sys: Closures</a></li><li><a href="../examples/performance.html"><strong aria-hidden="true">1.11.</strong> web-sys: performance.now</a></li><li><a href="../examples/fetch.html"><strong aria-hidden="true">1.12.</strong> web-sys: using fetch</a></li><li><a href="../examples/weather_report.html"><strong aria-hidden="true">1.13.</strong> web-sys: Weather report</a></li><li><a href="../examples/2d-canvas.html"><strong aria-hidden="true">1.14.</strong> web-sys: canvas hello world</a></li><li><a href="../examples/julia.html"><strong aria-hidden="true">1.15.</strong> web-sys: canvas Julia set</a></li><li><a href="../examples/web-audio.html"><strong aria-hidden="true">1.16.</strong> web-sys: WebAudio</a></li><li><a href="../examples/webgl.html"><strong aria-hidden="true">1.17.</strong> web-sys: WebGL</a></li><li><a href="../examples/websockets.html"><strong aria-hidden="true">1.18.</strong> web-sys: WebSockets</a></li><li><a href="../examples/webrtc_datachannel.html"><strong aria-hidden="true">1.19.</strong> web-sys: WebRTC DataChannel</a></li><li><a href="../examples/request-animation-frame.html"><strong aria-hidden="true">1.20.</strong> web-sys: requestAnimationFrame</a></li><li><a href="../examples/paint.html"><strong aria-hidden="true">1.21.</strong> web-sys: A Simple Paint Program</a></li><li><a href="../examples/wasm-in-web-worker.html" class="active"><strong aria-hidden="true">1.22.</strong> web-sys: Wasm in Web Worker</a></li><li><a href="../examples/raytrace.html"><strong aria-hidden="true">1.23.</strong> Parallel Raytracing</a></li><li><a href="../examples/wasm-audio-worklet.html"><strong aria-hidden="true">1.24.</strong> Wasm Audio Worklet</a></li><li><a href="../examples/todomvc.html"><strong aria-hidden="true">1.25.</strong> web-sys: A TODO MVC App</a></li></ol></li><li><a href="../reference/index.html"><strong aria-hidden="true">2.</strong> Reference</a></li><li><ol class="section"><li><a href="../reference/deployment.html"><strong aria-hidden="true">2.1.</strong> Deployment</a></li><li><a href="../reference/js-snippets.html"><strong aria-hidden="true">2.2.</strong> JS snippets</a></li><li><a href="../reference/static-js-objects.html"><strong aria-hidden="true">2.3.</strong> Static JS Objects</a></li><li><a href="../reference/passing-rust-closures-to-js.html"><strong aria-hidden="true">2.4.</strong> Passing Rust Closures to JS</a></li><li><a href="../reference/receiving-js-closures-in-rust.html"><strong aria-hidden="true">2.5.</strong> Receiving JS Closures in Rust</a></li><li><a href="../reference/js-promises-and-rust-futures.html"><strong aria-hidden="true">2.6.</strong> Promises and Futures</a></li><li><a href="../reference/iterating-over-js-values.html"><strong aria-hidden="true">2.7.</strong> Iterating over JS Values</a></li><li><a href="../reference/arbitrary-data-with-serde.html"><strong aria-hidden="true">2.8.</strong> Arbitrary Data with Serde</a></li><li><a href="../reference/accessing-properties-of-untyped-js-values.html"><strong aria-hidden="true">2.9.</strong> Accessing Properties of Untyped JS Values</a></li><li><a href="../reference/working-with-duck-typed-interfaces.html"><strong aria-hidden="true">2.10.</strong> Working with Duck-Typed Interfaces</a></li><li><a href="../reference/cli.html"><strong aria-hidden="true">2.11.</strong> Command Line Interface</a></li><li><a href="../reference/optimize-size.html"><strong aria-hidden="true">2.12.</strong> Optimizing for Size</a></li><li><a href="../reference/rust-targets.html"><strong aria-hidden="true">2.13.</strong> Supported Rust Targets</a></li><li><a href="../reference/browser-support.html"><strong aria-hidden="true">2.14.</strong> Supported Browsers</a></li><li><a href="../reference/weak-references.html"><strong aria-hidden="true">2.15.</strong> Support for Weak References</a></li><li><a href="../reference/reference-types.html"><strong aria-hidden="true">2.16.</strong> Support for Reference Types</a></li><li><a href="../reference/types.html"><strong aria-hidden="true">2.17.</strong> Supported Types</a></li><li><ol class="section"><li><a href="../reference/types/imported-js-types.html"><strong aria-hidden="true">2.17.1.</strong> Imported JavaScript Types</a></li><li><a href="../reference/types/exported-rust-types.html"><strong aria-hidden="true">2.17.2.</strong> Exported Rust Types</a></li><li><a href="../reference/types/jsvalue.html"><strong aria-hidden="true">2.17.3.</strong> JsValue</a></li><li><a href="../reference/types/boxed-slices.html"><strong aria-hidden="true">2.17.4.</strong> Box&lt;[T]&gt; and Vec<T></a></li><li><a href="../reference/types/pointers.html"><strong aria-hidden="true">2.17.5.</strong> *const T and *mut T</a></li><li><a href="../reference/types/non-null.html"><strong aria-hidden="true">2.17.6.</strong> NonNull<T></a></li><li><a href="../reference/types/numbers.html"><strong aria-hidden="true">2.17.7.</strong> Numbers</a></li><li><a href="../reference/types/bool.html"><strong aria-hidden="true">2.17.8.</strong> bool</a></li><li><a href="../reference/types/char.html"><strong aria-hidden="true">2.17.9.</strong> char</a></li><li><a href="../reference/types/str.html"><strong aria-hidden="true">2.17.10.</strong> str</a></li><li><a href="../reference/types/string.html"><strong aria-hidden="true">2.17.11.</strong> String</a></li><li><a href="../reference/types/number-slices.html"><strong aria-hidden="true">2.17.12.</strong> Number Slices</a></li><li><a href="../reference/types/boxed-number-slices.html"><strong aria-hidden="true">2.17.13.</strong> Boxed Number Slices</a></li><li><a href="../reference/types/result.html"><strong aria-hidden="true">2.17.14.</strong> Result&lt;T, E&gt;</a></li></ol></li><li><a href="../reference/attributes/index.html"><strong aria-hidden="true">2.18.</strong> #[wasm_bindgen] Attributes</a></li><li><ol class="section"><li><a href="../reference/attributes/on-js-imports/index.html"><strong aria-hidden="true">2.18.1.</strong> On JavaScript Imports</a></li><li><ol class="section"><li><a href="../reference/attributes/on-js-imports/catch.html"><strong aria-hidden="true">2.18.1.1.</strong> catch</a></li><li><a href="../reference/attributes/on-js-imports/constructor.html"><strong aria-hidden="true">2.18.1.2.</strong> constructor</a></li><li><a href="../reference/attributes/on-js-imports/extends.html"><strong aria-hidden="true">2.18.1.3.</strong> extends</a></li><li><a href="../reference/attributes/on-js-imports/getter-and-setter.html"><strong aria-hidden="true">2.18.1.4.</strong> getter and setter</a></li><li><a href="../reference/attributes/on-js-imports/final.html"><strong aria-hidden="true">2.18.1.5.</strong> final</a></li><li><a href="../reference/attributes/on-js-imports/indexing-getter-setter-deleter.html"><strong aria-hidden="true">2.18.1.6.</strong> indexing_getter, indexing_setter, and indexing_deleter</a></li><li><a href="../reference/attributes/on-js-imports/js_class.html"><strong aria-hidden="true">2.18.1.7.</strong> js_class = &quot;Blah&quot;</a></li><li><a href="../reference/attributes/on-js-imports/js_name.html"><strong aria-hidden="true">2.18.1.8.</strong> js_name</a></li><li><a href="../reference/attributes/on-js-imports/js_namespace.html"><strong aria-hidden="true">2.18.1.9.</strong> js_namespace</a></li><li><a href="../reference/attributes/on-js-imports/method.html"><strong aria-hidden="true">2.18.1.10.</strong> method</a></li><li><a href="../reference/attributes/on-js-imports/module.html"><strong aria-hidden="true">2.18.1.11.</strong> module = &quot;blah&quot;</a></li><li><a href="../reference/attributes/on-js-imports/raw_module.html"><strong aria-hidden="true">2.18.1.12.</strong> raw_module = &quot;blah&quot;</a></li><li><a href="../reference/attributes/on-js-imports/no_deref.html"><strong aria-hidden="true">2.18.1.13.</strong> no_deref</a></li><li><a href="../reference/attributes/on-js-imports/static_method_of.html"><strong aria-hidden="true">2.18.1.14.</strong> static_method_of = Blah</a></li><li><a href="../reference/attributes/on-js-imports/structural.html"><strong aria-hidden="true">2.18.1.15.</strong> structural</a></li><li><a href="../reference/attributes/on-js-imports/typescript_type.html"><strong aria-hidden="true">2.18.1.16.</strong> typescript_type</a></li><li><a href="../reference/attributes/on-js-imports/variadic.html"><strong aria-hidden="true">2.18.1.17.</strong> variadic</a></li><li><a href="../reference/attributes/on-js-imports/vendor_prefix.html"><strong aria-hidden="true">2.18.1.18.</strong> vendor_prefix</a></li></ol></li><li><a href="../reference/attributes/on-rust-exports/index.html"><strong aria-hidden="true">2.18.2.</strong> On Rust Exports</a></li><li><ol class="section"><li><a href="../reference/attributes/on-rust-exports/constructor.html"><strong aria-hidden="true">2.18.2.1.</strong> constructor</a></li><li><a href="../reference/attributes/on-rust-exports/js_name.html"><strong aria-hidden="true">2.18.2.2.</strong> js_name = Blah</a></li><li><a href="../reference/attributes/on-rust-exports/js_class.html"><strong aria-hidden="true">2.18.2.3.</strong> js_class = Blah</a></li><li><a href="../reference/attributes/on-rust-exports/readonly.html"><strong aria-hidden="true">2.18.2.4.</strong> readonly</a></li><li><a href="../reference/attributes/on-rust-exports/skip.html"><strong aria-hidden="true">2.18.2.5.</strong> skip</a></li><li><a href="../reference/attributes/on-rust-exports/skip_jsdoc.html"><strong aria-hidden="true">2.18.2.6.</strong> skip_jsdoc</a></li><li><a href="../reference/attributes/on-rust-exports/start.html"><strong aria-hidden="true">2.18.2.7.</strong> start</a></li><li><a href="../reference/attributes/on-rust-exports/main.html"><strong aria-hidden="true">2.18.2.8.</strong> main</a></li><li><a href="../reference/attributes/on-rust-exports/typescript_custom_section.html"><strong aria-hidden="true">2.18.2.9.</strong> typescript_custom_section</a></li><li><a href="../reference/attributes/on-rust-exports/getter-and-setter.html"><strong aria-hidden="true">2.18.2.10.</strong> getter and setter</a></li><li><a href="../reference/attributes/on-rust-exports/inspectable.html"><strong aria-hidden="true">2.18.2.11.</strong> inspectable</a></li><li><a href="../reference/attributes/on-rust-exports/skip_typescript.html"><strong aria-hidden="true">2.18.2.12.</strong> skip_typescript</a></li><li><a href="../reference/attributes/on-rust-exports/getter_with_clone.html"><strong aria-hidden="true">2.18.2.13.</strong> getter_with_clone</a></li><li><a href="../reference/attributes/on-rust-exports/unchecked_type.html"><strong aria-hidden="true">2.18.2.14.</strong> unchecked_return_type and unchecked_param_type</a></li><li><a href="../reference/attributes/on-rust-exports/description.html"><strong aria-hidden="true">2.18.2.15.</strong> return_description and param_description</a></li></ol></li></ol></li></ol></li><li><a href="../web-sys/index.html"><strong aria-hidden="true">3.</strong> web-sys</a></li><li><ol class="section"><li><a href="../web-sys/using-web-sys.html"><strong aria-hidden="true">3.1.</strong> Using web-sys</a></li><li><a href="../web-sys/cargo-features.html"><strong aria-hidden="true">3.2.</strong> Cargo Features</a></li><li><a href="../web-sys/function-overloads.html"><strong aria-hidden="true">3.3.</strong> Function Overloads</a></li><li><a href="../web-sys/type-translations.html"><strong aria-hidden="true">3.4.</strong> Type Translations</a></li><li><a href="../web-sys/inheritance.html"><strong aria-hidden="true">3.5.</strong> Inheritance</a></li><li><a href="../web-sys/unstable-apis.html"><strong aria-hidden="true">3.6.</strong> Unstable APIs</a></li></ol></li><li><a href="../wasm-bindgen-test/index.html"><strong aria-hidden="true">4.</strong> Testing with wasm-bindgen-test</a></li><li><ol class="section"><li><a href="../wasm-bindgen-test/usage.html"><strong aria-hidden="true">4.1.</strong> Usage</a></li><li><a href="../wasm-bindgen-test/asynchronous-tests.html"><strong aria-hidden="true">4.2.</strong> Writing Asynchronous Tests</a></li><li><a href="../wasm-bindgen-test/browsers.html"><strong aria-hidden="true">4.3.</strong> Testing in Headless Browsers</a></li><li><a href="../wasm-bindgen-test/continuous-integration.html"><strong aria-hidden="true">4.4.</strong> Continuous Integration</a></li><li><a href="../wasm-bindgen-test/coverage.html"><strong aria-hidden="true">4.5.</strong> Coverage (Experimental)</a></li></ol></li><li><a href="../contributing/index.html"><strong aria-hidden="true">5.</strong> Contributing to wasm-bindgen</a></li><li><ol class="section"><li><a href="../contributing/testing.html"><strong aria-hidden="true">5.1.</strong> Testing</a></li><li><a href="../contributing/design/index.html"><strong aria-hidden="true">5.2.</strong> Internal Design</a></li><li><ol class="section"><li><a href="../contributing/design/js-objects-in-rust.html"><strong aria-hidden="true">5.2.1.</strong> JS Objects in Rust</a></li><li><a href="../contributing/design/exporting-rust.html"><strong aria-hidden="true">5.2.2.</strong> Exporting a function to JS</a></li><li><a href="../contributing/design/exporting-rust-struct.html"><strong aria-hidden="true">5.2.3.</strong> Exporting a struct to JS</a></li><li><a href="../contributing/design/importing-js.html"><strong aria-hidden="true">5.2.4.</strong> Importing a function from JS</a></li><li><a href="../contributing/design/importing-js-struct.html"><strong aria-hidden="true">5.2.5.</strong> Importing a class from JS</a></li><li><a href="../contributing/design/rust-type-conversions.html"><strong aria-hidden="true">5.2.6.</strong> Rust Type conversions</a></li><li><a href="../contributing/design/describe.html"><strong aria-hidden="true">5.2.7.</strong> Types in wasm-bindgen</a></li></ol></li><li><a href="../contributing/js-sys/index.html"><strong aria-hidden="true">5.3.</strong> js-sys</a></li><li><ol class="section"><li><a href="../contributing/js-sys/testing.html"><strong aria-hidden="true">5.3.1.</strong> Testing</a></li><li><a href="../contributing/js-sys/adding-more-apis.html"><strong aria-hidden="true">5.3.2.</strong> Adding More APIs</a></li></ol></li><li><a href="../contributing/web-sys/index.html"><strong aria-hidden="true">5.4.</strong> web-sys</a></li><li><ol class="section"><li><a href="../contributing/web-sys/overview.html"><strong aria-hidden="true">5.4.1.</strong> Overview</a></li><li><a href="../contributing/web-sys/testing.html"><strong aria-hidden="true">5.4.2.</strong> Testing</a></li><li><a href="../contributing/web-sys/logging.html"><strong aria-hidden="true">5.4.3.</strong> Logging</a></li><li><a href="../contributing/web-sys/supporting-more-web-apis.html"><strong aria-hidden="true">5.4.4.</strong> Supporting More Web APIs</a></li></ol></li><li><a href="../contributing/publishing.html"><strong aria-hidden="true">5.5.</strong> Publishing</a></li><li><a href="../contributing/team.html"><strong aria-hidden="true">5.6.</strong> Team</a></li></ol></li></ol>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                <style>
  header.warning {
    background-color: rgb(242, 222, 222);
    border-bottom-color: rgb(238, 211, 215);
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px;
    border-bottom-style: solid;
    border-bottom-width: 0.666667px;
    border-image-outset: 0 0 0 0;
    border-image-repeat: stretch stretch;
    border-image-slice: 100% 100% 100% 100%;
    border-image-source: none;
    border-image-width: 1 1 1 1;
    border-left-color: rgb(238, 211, 215);
    border-left-style: solid;
    border-left-width: 0.666667px;
    border-right-color: rgb(238, 211, 215);
    border-right-style: solid;
    border-right-width: 0.666667px;
    border-top-color: rgb(238, 211, 215);
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
    border-top-style: solid;
    border-top-width: 0.666667px;
    color: rgb(185, 74, 72);
    margin-bottom: 0px;
    margin-left: 0px;
    margin-right: 0px;
    margin-top: 30px;
    padding-bottom: 8px;
    padding-left: 14px;
    padding-right: 35px;
    padding-top: 8px;
    text-align: center;
  }
</style>
<header class='warning'>
  This documentation is
  <a
  href="https://blog.rust-lang.org/inside-rust/2025/07/21/sunsetting-the-rustwasm-github-org/">no
  longer maintained at this domain</a>, and is now maintained
  <a href="https://wasm-bindgen.github.io/wasm-bindgen/">
  at wasm-bindgen.github.io</a> instead.
</header>

                <div id="menu-bar" class="menu-bar">
                    <div id="menu-bar-sticky-container">
                        <div class="left-buttons">
                            <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                                <i class="fa fa-bars"></i>
                            </button>
                            <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                                <i class="fa fa-paint-brush"></i>
                            </button>
                            <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                                <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                                <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                                <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                                <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                                <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                            </ul>
                            
                        </div>

                        <h1 class="menu-title">The `wasm-bindgen` Guide</h1> 

                        <div class="right-buttons">
                            <a href="../print.html" title="Print this book" aria-label="Print this book">
                                <i id="print-button" class="fa fa-print"></i>
                            </a>
                            
                        </div>
                    </div>
                </div>

                

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <a class="header" href="#wasm-in-web-worker" id="wasm-in-web-worker"><h1>Wasm in Web Worker</h1></a>
<p><a href="https://github.com/rustwasm/wasm-bindgen/tree/master/examples/wasm-in-web-worker">View full source code</a></p>
<p>A simple example of parallel execution by spawning a web worker with <code>web_sys</code>,
loading Wasm code in the web worker and interacting between the main thread and
the worker.</p>
<a class="header" href="#building--compatibility" id="building--compatibility"><h2>Building &amp; compatibility</h2></a>
<p>At the time of this writing, only Chrome supports modules in web workers, e.g.
Firefox does not. To have compatibility across browsers, the whole example is
set up without relying on ES modules as target. Therefore we have to build
with <code>--target no-modules</code>. The full command can be found in <code>build.sh</code>.</p>
<a class="header" href="#cargotoml" id="cargotoml"><h2><code>Cargo.toml</code></h2></a>
<p>The <code>Cargo.toml</code> enables features necessary to work with the DOM, log output to
the JS console, creating a worker and reacting to message events.</p>
<pre><code class="language-toml">[package]
authors = [&quot;The wasm-bindgen Developers&quot;]
edition = &quot;2021&quot;
name = &quot;wasm-in-web-worker&quot;
publish = false
version = &quot;0.0.0&quot;

[lib]
crate-type = [&quot;cdylib&quot;]

[dependencies]
console_error_panic_hook = { version = &quot;0.1.6&quot;, optional = true }
wasm-bindgen = { path = &quot;../../&quot; }

[dependencies.web-sys]
features = [
  'console',
  'Document',
  'HtmlElement',
  'HtmlInputElement',
  'MessageEvent',
  'Window',
  'Worker',
]
path = &quot;../../crates/web-sys&quot;

[lints]
workspace = true

</code></pre>
<a class="header" href="#srclibrs" id="srclibrs"><h2><code>src/lib.rs</code></h2></a>
<p>Creates a struct <code>NumberEval</code> with methods to act as stateful object in the
worker and function <code>startup</code> to be launched in the main thread. Also includes
internal helper functions <code>setup_input_oninput_callback</code> to attach a
<code>wasm_bindgen::Closure</code> as callback to the <code>oninput</code> event of the input field
and <code>get_on_msg_callback</code> to create a <code>wasm_bindgen::Closure</code> which is triggered
when the worker returns a message.</p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
use std::cell::RefCell;
use std::rc::Rc;
use wasm_bindgen::prelude::*;
use web_sys::{console, HtmlElement, HtmlInputElement, MessageEvent, Worker};

/// A number evaluation struct
///
/// This struct will be the main object which responds to messages passed to the
/// worker. It stores the last number which it was passed to have a state. The
/// statefulness is not required in this example but should show how
/// larger, more complex scenarios with statefulness can be set up.
#[wasm_bindgen]
pub struct NumberEval {
    number: i32,
}

#[wasm_bindgen]
impl NumberEval {
    /// Create new instance.
    pub fn new() -&gt; NumberEval {
        NumberEval { number: 0 }
    }

    /// Check if a number is even and store it as last processed number.
    ///
    /// # Arguments
    ///
    /// * `number` - The number to be checked for being even/odd.
    pub fn is_even(&amp;mut self, number: i32) -&gt; bool {
        self.number = number;
        self.number % 2 == 0
    }

    /// Get last number that was checked - this method is added to work with
    /// statefulness.
    pub fn get_last_number(&amp;self) -&gt; i32 {
        self.number
    }
}

/// Run entry point for the main thread.
#[wasm_bindgen]
pub fn startup() {
    // Here, we create our worker. In a larger app, multiple callbacks should be
    // able to interact with the code in the worker. Therefore, we wrap it in
    // `Rc&lt;RefCell&gt;` following the interior mutability pattern. Here, it would
    // not be needed but we include the wrapping anyway as example.
    let worker_handle = Rc::new(RefCell::new(Worker::new(&quot;./worker.js&quot;).unwrap()));
    console::log_1(&amp;&quot;Created a new worker from within Wasm&quot;.into());

    // Pass the worker to the function which sets up the `oninput` callback.
    setup_input_oninput_callback(worker_handle);
}

fn setup_input_oninput_callback(worker: Rc&lt;RefCell&lt;web_sys::Worker&gt;&gt;) {
    let document = web_sys::window().unwrap().document().unwrap();

    // If our `onmessage` callback should stay valid after exiting from the
    // `oninput` closure scope, we need to either forget it (so it is not
    // destroyed) or store it somewhere. To avoid leaking memory every time we
    // want to receive a response from the worker, we move a handle into the
    // `oninput` closure to which we will always attach the last `onmessage`
    // callback. The initial value will not be used and we silence the warning.
    #[allow(unused_assignments)]
    let mut persistent_callback_handle = get_on_msg_callback();

    let callback = Closure::new(move || {
        console::log_1(&amp;&quot;oninput callback triggered&quot;.into());
        let document = web_sys::window().unwrap().document().unwrap();

        let input_field = document
            .get_element_by_id(&quot;inputNumber&quot;)
            .expect(&quot;#inputNumber should exist&quot;);
        let input_field = input_field
            .dyn_ref::&lt;HtmlInputElement&gt;()
            .expect(&quot;#inputNumber should be a HtmlInputElement&quot;);

        // If the value in the field can be parsed to a `i32`, send it to the
        // worker. Otherwise clear the result field.
        match input_field.value().parse::&lt;i32&gt;() {
            Ok(number) =&gt; {
                // Access worker behind shared handle, following the interior
                // mutability pattern.
                let worker_handle = &amp;*worker.borrow();
                let _ = worker_handle.post_message(&amp;number.into());
                persistent_callback_handle = get_on_msg_callback();

                // Since the worker returns the message asynchronously, we
                // attach a callback to be triggered when the worker returns.
                worker_handle
                    .set_onmessage(Some(persistent_callback_handle.as_ref().unchecked_ref()));
            }
            Err(_) =&gt; {
                document
                    .get_element_by_id(&quot;resultField&quot;)
                    .expect(&quot;#resultField should exist&quot;)
                    .dyn_ref::&lt;HtmlElement&gt;()
                    .expect(&quot;#resultField should be a HtmlInputElement&quot;)
                    .set_inner_text(&quot;&quot;);
            }
        }
    });

    // Attach the closure as `oninput` callback to the input field.
    document
        .get_element_by_id(&quot;inputNumber&quot;)
        .expect(&quot;#inputNumber should exist&quot;)
        .dyn_ref::&lt;HtmlInputElement&gt;()
        .expect(&quot;#inputNumber should be a HtmlInputElement&quot;)
        .set_oninput(Some(callback.as_ref().unchecked_ref()));

    // Leaks memory.
    callback.forget();
}

/// Create a closure to act on the message returned by the worker
fn get_on_msg_callback() -&gt; Closure&lt;dyn FnMut(MessageEvent)&gt; {
    Closure::new(move |event: MessageEvent| {
        console::log_2(&amp;&quot;Received response: &quot;.into(), &amp;event.data());

        let result = match event.data().as_bool().unwrap() {
            true =&gt; &quot;even&quot;,
            false =&gt; &quot;odd&quot;,
        };

        let document = web_sys::window().unwrap().document().unwrap();
        document
            .get_element_by_id(&quot;resultField&quot;)
            .expect(&quot;#resultField should exist&quot;)
            .dyn_ref::&lt;HtmlElement&gt;()
            .expect(&quot;#resultField should be a HtmlInputElement&quot;)
            .set_inner_text(result);
    })
}

#}</code></pre></pre>
<a class="header" href="#indexhtml" id="indexhtml"><h2><code>index.html</code></h2></a>
<p>Includes the input element <code>#inputNumber</code> to type a number into and a HTML
element <code>#resultField</code> were the result of the evaluation even/odd is written to.
Since we require to build with <code>--target no-modules</code> to be able to load Wasm
code in the worker across browsers, the <code>index.html</code> also includes loading
both <code>wasm_in_web_worker.js</code> and <code>index.js</code>.</p>
<pre><code class="language-html">&lt;html&gt;

&lt;head&gt;
    &lt;meta content=&quot;text/html;charset=utf-8&quot; http-equiv=&quot;Content-Type&quot; /&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;div id=&quot;wrapper&quot;&gt;
        &lt;h1&gt;Main Thread/Wasm Web Worker Interaction&lt;/h1&gt;

        &lt;input type=&quot;text&quot; id=&quot;inputNumber&quot;&gt;

        &lt;div id=&quot;resultField&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;

    &lt;!-- Make `wasm_bindgen` available for `index.js` --&gt;
    &lt;script src='./pkg/wasm_in_web_worker.js'&gt;&lt;/script&gt;
    &lt;!-- Note that there is no `type=&quot;module&quot;` in the script tag --&gt;
    &lt;script src=&quot;./index.js&quot;&gt;&lt;/script&gt;

&lt;/body&gt;

&lt;/html&gt;
</code></pre>
<a class="header" href="#indexjs" id="indexjs"><h2><code>index.js</code></h2></a>
<p>Loads our Wasm file asynchronously and calls the entry point <code>startup</code> of the
main thread which will create a worker.</p>
<pre><code class="language-js">// We only need `startup` here which is the main entry point
// In theory, we could also use all other functions/struct types from Rust which we have bound with
// `#[wasm_bindgen]`
const {startup} = wasm_bindgen;

async function run_wasm() {
    // Load the Wasm file by awaiting the Promise returned by `wasm_bindgen`
    // `wasm_bindgen` was imported in `index.html`
    await wasm_bindgen();

    console.log('index.js loaded');

    // Run main Wasm entry point
    // This will create a worker from within our Rust code compiled to Wasm
    startup();
}

run_wasm();

</code></pre>
<a class="header" href="#workerjs" id="workerjs"><h2><code>worker.js</code></h2></a>
<p>Loads our Wasm file by first importing <code>wasm_bindgen</code> via
<code>importScripts('./pkg/wasm_in_web_worker.js')</code> and then awaiting the Promise
returned by <code>wasm_bindgen(...)</code>. Creates a new object to do the background
calculation and bind a method of the object to the <code>onmessage</code> callback of the
worker.</p>
<pre><code class="language-js">// The worker has its own scope and no direct access to functions/objects of the
// global scope. We import the generated JS file to make `wasm_bindgen`
// available which we need to initialize our Wasm code.
importScripts('./pkg/wasm_in_web_worker.js');

console.log('Initializing worker')

// In the worker, we have a different struct that we want to use as in
// `index.js`.
const {NumberEval} = wasm_bindgen;

async function init_wasm_in_worker() {
    // Load the Wasm file by awaiting the Promise returned by `wasm_bindgen`.
    await wasm_bindgen('./pkg/wasm_in_web_worker_bg.wasm');

    // Create a new object of the `NumberEval` struct.
    var num_eval = NumberEval.new();

    // Set callback to handle messages passed to the worker.
    self.onmessage = async event =&gt; {
        // By using methods of a struct as reaction to messages passed to the
        // worker, we can preserve our state between messages.
        var worker_result = num_eval.is_even(event.data);

        // Send response back to be handled by callback in main thread.
        self.postMessage(worker_result);
    };
};

init_wasm_in_worker();

</code></pre>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                        
                            <a rel="prev" href="../examples/paint.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>
                        

                        
                            <a rel="next" href="../examples/raytrace.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>
                        

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                
                    <a href="../examples/paint.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>
                

                
                    <a href="../examples/raytrace.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
                
            </nav>

        </div>

        

        

        

        

        <script src="../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="../book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->
        

        

    </body>
</html>
